package eclipse.util.io;
import eclipse.util.*;
import java.io.*;
import java.net.*;
import java.util.Random;

import eclipse.ErrorManager;
/**
 * IOTools is a class of static methods that can be used to modify any form of files on the system.
 */
/*
 * Copyright (c) 2009, TOD Productions All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *	- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *	- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *	-Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
public final class IOTools 
{
	/**
	 * Reads an entire file as a single String.
	 * @param sFile String path to the file.
	 */
	public static final String readAsString(String sFile)
	{
		//Attempt to read the file as a String
		try
		{
			//build a buffer for the file
	        final StringBuffer fileData = new StringBuffer(1000);
	        //Reader object for the buffer
	        final BufferedReader reader = new BufferedReader(new FileReader(sFile));
	        //buffer for parsing the file
	        char[] buf = new char[1024];
	        //token position in the file
	        int numRead=0;
	        //read the file until the buffer is empty
	        while((numRead=reader.read(buf)) != -1)
	        {
	        	//read the string as a String
	            String readData = String.valueOf(buf, 0, numRead);
	            //add the string to the buffer
	            fileData.append(readData);
	            //clear the Character Buffer
	            buf = new char[1024];
	        }
	        //close the file
	        reader.close();
	        //return the file as a String
	        return fileData.toString();
		}
		//An error happened so handle it.
		catch(Exception e)
		{
			//Handle the error
			ErrorManager.handleError(e);
			//return a blank String
			return "";
		}
	}
	/**
	 * Reads an entire file as an array of bytes.
	 * @param sFile String path pointing to the file.
	 */
	 public static final byte[] readAsBytes(String sFile)
	 {		 		 
		 //default value
		 byte[] bytes = new byte[0];
		 //Attempt to read the file
		 try
		 {
			//File object representing the File
			final File file = new File(sFile);
			//size of the file
			final long length = file.length();
			//reset the size of the byte array to the size of the file
			bytes = new byte[(int)length];
			//create an input stream from the File
	        final InputStream is = new FileInputStream(file);
	        
	        //related to the offset of the input
	        int offset = 0;	        
	        //lines read
	        int numRead = 0;
	        //specify if the file is too big and create an error instance
	        if(length > Integer.MAX_VALUE)	        
	        	throw new IOException("File is too large!");	        	           
	        //Scan through the file reading each byte	        
	        while (offset < bytes.length
	               && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) 
	        {
	        	//increase the offset value
	            offset += numRead;
	        }
	    
	        // Ensure all the bytes have been read in
	        if (offset < bytes.length) 
	        {
	            throw new IOException("Could not completely read file "+file.getName());
	        }
	    
	        // Close the input stream and return bytes
	        is.close();
		 }
		 //Handle the error
		 catch(Exception e)
		 {
			 ErrorManager.handleError(e);
		 }	 
		 //return the ByteArray
		 return bytes;
	}
	 /**
	  * Writes an array of bytes to a file.
	  * @param sFile String path to the file.
	  * @param byteArray Array of bytes to be written to the file.
	  */
	public static final void writeBytesToFile(String sFile, byte[] byteArray)
	{
		//Attempt to write an array of bytes to a file
		try
		{
			//Create an output stream to dump the bytes into
			FileOutputStream fos = new FileOutputStream(sFile);
			//write the array to the output stream
			fos.write(byteArray);
			//force all bytes to be written to the output stream
			fos.flush();
			//close the output stream once writting is done
			fos.close();			
		}
		//Catch and handle any errors
		catch(Exception e)
		{
			//An error occurred so have the ErrorManager handle it
			eclipse.ErrorManager.handleError(e);
		}
	}
	/**
	 * Creates a new file. If the file already exists, it deletes it first.
	 * @param sFile String path to the file. 
	 */
	public static final void makeFile(String sFile)
	{
		//Check to confirm the file does not exist
		if(fileExists(sFile))
		{
			//The file exists, so delete it.
			killFile(sFile);
		}
		//dumps a null String into the file, this should make it.
		new DataFile(sFile).writeString("");			
	 }
	public static final boolean dirExists(String sDir)
	{
		//Same as fileExists since a directory is technically a file.
		return fileExists(sDir);
	}
	/**
	 * Creates a new directory.
	 * @param sDir
	 */
	public static final void makeDir(String sDir)
	{
		//Builds a File object then proceeds to making a directory.
		new File(sDir).mkdir();
	}
	/**
	 * Returns a list of Files in the specified directory.
	 * @param directory String path for a specific directory.
	 */
	public static final File[] getFiles(String directory)
	{
		//build a File object to use for reading the directory
		final File folder = new File(directory);

		//populate the list of files by finding each file within the directory
		final File[] listOfFiles = folder.listFiles();
		 
		//Return the list of files
		return listOfFiles;   		  
	}	
	/**
	 * Deletes a specific file.
	 * @param sFile String path to a file.
	 */
	public static final void killFile(String sFile)
	{
		//Build a File object using a String-path and delete it if it exists
		new File(sFile).delete();			
	}
	/**
	 * Returns true if the file exists, otherwise it returns false.
	 * @param sFile String path to the specific file.
	 */
	public static final boolean fileExists(String sFile)
	{
		//Build a File object using a String-path and determine if it exists
		return new File(sFile).exists();
	}
	/**
	 * Modifies a file and makes it a temporary file.
	 * @param sFile File's String-path to set as temporary
	 */
	public static final void setFileAsTemporary(String sFile)
	{
		//build a File object using a String-path and set it as being a temporary file.
		new File(sFile).deleteOnExit();
	}
	
	/**
	 * Download a file using a String-path.
	 * This is not recommended to use because it is a wrapper for download(URL, String)
	 * @param sAddress String-path pointing to the file
	 * @param sFile What to name the file once its done downloading
	 */
	public static final void download(String sAddress, String sFile)
	{
		//attempt to download a file by constructing a url and using the download(URL, String) method
		try
		{
			//Construct a url based off of the String-path provided
			final URL url = new URL(sAddress);
			//Call the url-based download function to download the file
			download(url, sFile);
		}
		//An error occurred so handle it
		catch(Exception e)
		{
			//An error occurred so send it to the ErrorManager to handle
			ErrorManager.handleError(e);
		}
	}
	/**
	 * Downloads a file using an ERL
	 * @param eAddress ERL that points to the file
	 * @param file What to name the file once its done downloading
	 */
	public static final void download(ERL eAddress, String file)
	{
		//attempt to download a file using an ERL
		try
		{
			//Stream to send the data to. This is the file to create
			final OutputStream 	out = new BufferedOutputStream(new FileOutputStream(file));
			//Stream containing the file to download. This is obtained from the ERL address
			final InputStream		in  = eAddress.openStream();
			
			//buffer used to store data. 1024 bytes = 1kb
			byte[] buffer = new byte[1024];
			
			//if c = -1 then the file has no more data to read
			int c;
			
			//Read from the input stream until there is no more data
			while((c = in.read(buffer)) != -1)	
			{
				//Write the data to the output stream
				out.write(buffer, 0, c);
			}
			//Close the input stream because we are done with it
			in.close();
			//Close the output stream because we are done with it
			out.close();
		}
		//An error occurred while downloading the file so handle it
		catch(Exception e)
		{
			//Send the error to the ErrorManager
			ErrorManager.handleError(e);
		}
	}
	/**
	 * Downloads a file using a URL and saves the file as the specified String, file
	 * @param uAddress Address to the file to download
	 * @param file What to name the file after downloading
	 */
	public static final void download(URL uAddress, String file)
	{
		//Attempt to download the file from the URL
		try
		{
			//Construct an output stream to dump the data to
			final OutputStream 	out = new BufferedOutputStream(new FileOutputStream(file));
			//Construct an input stream to read the file, get this from the URL
			final InputStream		in  = uAddress.openStream();
			
			//Construct a byte-buffer to store data while reading
			byte[] buffer = new byte[1024];
			
			//if c = -1, then the file is done being read
			int c;
			
			//Read the file for all data
			while((c = in.read(buffer)) != -1)
			{
				//write the data to the output stream
				out.write(buffer, 0, c);
			}
			//close the input stream because we are done with it
			in.close();
			//close the output stream because we are done with it
			out.close();
		}
		//An error occurred while downloading the file, so handle it.
		catch(Exception e)
		{
			//An error occurred so handle it
			ErrorManager.handleError(e);
		}
	}
	/**
	 * Produces a random integer between the low/high values
	 * @param low Minimum value that the integer can be
	 * @param high Maximum value that the integer can be
	 * @return Randomly generated integer
	 */
	public static final int random(int low, int high)
	{
		//Build a new Random object
		final Random rand = new Random();
		//Generate the Random number
		return (int)((high - low + 1) * rand.nextFloat()) + low;
	}			
	/**
	 * Replaces multiple subStrings with a single new subString
	 * @param str String to modify
	 * @param newChar subString to replace with
	 * @param oldChar array of old subStrings to replace
	 * @return The new, formatted String
	 */
	public static final String strReplace(String str, String newChar, String ... oldChar)
	{			
		//Scroll through the values of the characters to replace
		for(int i = 0; i < oldChar.length; i++)
		{
			//replace the old subStrings with the new subStrings
			str = str.replace(oldChar[i], newChar);
		}
		//return the formatted String
		return str;
	}
}